package cc.shacocloud.mirage.restful;

import cc.shacocloud.mirage.bean.BeanFactory;
import cc.shacocloud.mirage.core.ApplicationContext;
import cc.shacocloud.mirage.restful.bind.ConfigurableWebBindingInitializer;
import cc.shacocloud.mirage.restful.bind.annotation.Controller;
import cc.shacocloud.mirage.restful.bind.annotation.ControllerAdvice;
import cc.shacocloud.mirage.restful.bind.annotation.WebInterceptor;
import cc.shacocloud.mirage.restful.bind.converter.json.Jackson2ObjectMapperBuilder;
import cc.shacocloud.mirage.restful.bind.converter.json.JacksonHttpMessageConverter;
import cc.shacocloud.mirage.restful.bind.support.*;
import cc.shacocloud.mirage.restful.bind.validation.SmartValidator;
import cc.shacocloud.mirage.restful.bind.validation.SmartValidatorImpl;
import cc.shacocloud.mirage.restful.http.HttpMessageConverter;
import cc.shacocloud.mirage.utils.annotation.AnnotatedElementUtils;
import cc.shacocloud.mirage.utils.charSequence.StrUtil;
import cc.shacocloud.mirage.utils.converter.ConversionRegistry;
import cc.shacocloud.mirage.utils.converter.TypeConverterSupport;
import cc.shacocloud.mirage.utils.converter.TypeConverterSupportImpl;
import cc.shacocloud.mirage.utils.reflection.ParameterNameDiscoverer;
import cc.shacocloud.mirage.utils.reflection.ReflectUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.templ.freemarker.FreeMarkerTemplateEngine;
import jakarta.validation.Validation;
import jakarta.validation.ValidatorFactory;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.HibernateValidator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Method;
import java.util.*;

/**
 * 基于 mirage-bean 模块装载需要的对象
 */
@Slf4j
public class MirageRequestMappingHandler extends VertxRouterRequestMappingMappingRequestHandler {
    
    // http 消息转换器
    @Getter
    private final List<HttpMessageConverter<?>> httpMessageConverters;
    
    // 拦截器映射信息
    @Getter
    private final List<InterceptorMappingInfo> interceptorMappings;
    
    // 异常处理程序解析器
    @Getter
    private final List<HandlerExceptionResolver> exceptionResolvers;
    
    // restful 配置器
    @Getter
    private final List<MirageRestfulConfigurer> restfulConfigurer = new ArrayList<>();
    
    // 基于 {@link ExceptionHandler} 的异常解析器
    @Getter
    private final ExceptionHandlerExceptionResolver exceptionHandlerExceptionResolver;
    
    // 异常处理器
    @Getter
    private final List<Object> exceptionHandler = new ArrayList<>();
    
    // 静态资源处理器注册程序
    @Getter
    private final StaticResourceHandlerRegistry staticResourceHandlerRegistry = new StaticResourceHandlerRegistry();
    
    // 参数验证器
    @Getter
    @Nullable
    private SmartValidator validator;
    
    // 类型转换器
    @Setter
    @Getter
    private TypeConverterSupport typeConverterSupport;
    
    @Getter
    private final ObjectMapper objectMapper;
    
    private final Vertx vertx;
    
    public MirageRequestMappingHandler(Vertx vertx, ParameterNameDiscoverer parameterNameDiscoverer) {
        this(vertx, parameterNameDiscoverer, Jackson2ObjectMapperBuilder.json().build());
    }
    
    public MirageRequestMappingHandler(Vertx vertx,
                                       ParameterNameDiscoverer parameterNameDiscoverer,
                                       ObjectMapper objectMapper) {
        super(parameterNameDiscoverer);
        this.vertx = vertx;
        this.httpMessageConverters = new ArrayList<>();
        this.interceptorMappings = new ArrayList<>();
        this.exceptionResolvers = new ArrayList<>();
        this.exceptionHandlerExceptionResolver = new ExceptionHandlerExceptionResolver();
        this.objectMapper = objectMapper;
    }
    
    /**
     * 设置参数验证器
     */
    public void setValidator(@Nullable SmartValidator validator) {
        this.validator = validator;
    }
    
    // ---------------------- 方便子类拓展的默认方法，不建议使用者调用这些实现，这是给程序框架拓展留有的
    
    /**
     * 默认转换器注册表，子类可以自行拓展
     */
    protected void defaultConversionRegistry(@NotNull Vertx vertx,
                                             @NotNull ConversionRegistry conversionRegistry) {
    }
    
    /**
     * 默认异常解析器，子类可以自行拓展
     */
    protected void defaultExceptionResolvers(@NotNull Vertx vertx,
                                             @NotNull List<HandlerExceptionResolver> exceptionResolvers) {
        exceptionResolvers.add(new JsonHandlerExceptionResolver(objectMapper));
        exceptionResolvers.add(new FreeMarkerTemplateHandlerExceptionResolver(FreeMarkerTemplateEngine.create(vertx)));
    }
    
    /**
     * 默认请求拦截器，子类可以自行拓展
     */
    protected void defaultInterceptorMappings(@NotNull Vertx vertx,
                                              @NotNull List<InterceptorMappingInfo> interceptorMappings) {
    }
    
    /**
     * 默认http消息转换器，子类可以自行拓展
     */
    protected void defaultHttpMessageConverters(@NotNull Vertx vertx,
                                                @NotNull List<HttpMessageConverter<?>> httpMessageConverters) {
        httpMessageConverters.add(new JacksonHttpMessageConverter(objectMapper));
    }
    
    /**
     * @return {@link ConfigurableWebBindingInitializer} ，子类可以自行拓展
     */
    protected ConfigurableWebBindingInitializer createWebBindingInitializer(Vertx vertx) {
        return new ConfigurableWebBindingInitializer();
    }
    
    /**
     * 默认异常处理解析器，子类可以自行拓展
     */
    protected void defaultExceptionHandlerExceptionResolver(@NotNull Vertx vertx,
                                                            @NotNull ExceptionHandlerExceptionResolver exceptionResolver) {
    }
    
    /**
     * 默认方法结果处理器，子类可以自行拓展
     */
    protected void defaultMethodReturnValueHandler(@NotNull Vertx vertx,
                                                   @NotNull HandleMethodReturnValueHandlerComposite returnValueHandlerComposite) {
        returnValueHandlerComposite.addHandler(new BufferHandleMethodReturnValueHandler());
    }
    
    /**
     * 默认方法参数解析器，子类可以自行拓展
     */
    protected void defaultMethodArgumentResolver(@NotNull Vertx vertx,
                                                 @NotNull HandleMethodArgumentResolverComposite handleMethodArgumentResolverComposite) {
        handleMethodArgumentResolverComposite.addResolver(new QueryParamsAndFormAttributesMethodArgumentResolver(objectMapper));
        handleMethodArgumentResolverComposite.addResolver(new PathVariableMethodArgumentResolver());
        handleMethodArgumentResolverComposite.addResolver(new RequestHeaderMethodArgumentResolver());
        handleMethodArgumentResolverComposite.addResolver(new MultipartFileUploadArgumentResolver());
        handleMethodArgumentResolverComposite.addResolver(new BindingResultMethodArgumentResolver());
    }
    
    /**
     * 注册默认静态资源处理器，子类可以自行拓展
     */
    protected void defaultStaticResourceHandler(@NotNull StaticResourceHandlerRegistry staticResourceHandlerRegistry) {
    
    }
    
    /**
     * 默认参数验证器
     */
    protected SmartValidator defaultValidator(@NotNull Vertx vertx) {
        try (ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
                .configure()
                .failFast(false)
                .buildValidatorFactory()) {
            
            return new SmartValidatorImpl(validatorFactory.getValidator());
        }
    }
    
    /**
     * 默认的类型转换器
     */
    protected TypeConverterSupport defaultTypeConverter(@NotNull Vertx vertx) {
        BeanFactory beanFactory = obtainApplicationContext();
        
        if (Objects.nonNull(beanFactory) && beanFactory.containsBean(TypeConverterSupport.class)) {
            return beanFactory.getBean(TypeConverterSupport.class);
        }
        
        return new TypeConverterSupportImpl();
    }
    
    // ---------------------------- 内部流程
    
    
    @Override
    public void init() {
        // 初始化请求映射
        initRequestMappingRequestHandler();
    }
    
    @Override
    public Future<Void> bindRouterMapping(Router router) {
        // 先绑定基于 HandlerMethod 的路由
        return super.bindRouterMapping(router)
                // 接着绑定静态资源路由
                .compose(r -> {
                    for (Map.Entry<RequestMappingInfo, StaticResourceHandler> entry : staticResourceHandlerRegistry.getStaticResourceHandlerMap().entrySet()) {
                        RequestMappingInfo mappingInfo = entry.getKey();
                        
                        VertxInvokeStaticResourceHandler vertxInvokeStaticResourceHandler = new VertxInvokeStaticResourceHandler(entry.getValue());
                        bindInvocableHandlerMethod(vertxInvokeStaticResourceHandler);
                        
                        HandlerExecutionChain handler = createHandlerExecutionChain(vertxInvokeStaticResourceHandler, mappingInfo);
                        bindRouterHandler(router, mappingInfo, handler);
                    }
                    return Future.succeededFuture();
                });
    }
    
    /**
     * 初始化请求映射处理器
     */
    protected void initRequestMappingRequestHandler() {
        // 类型转换器支持
        if (Objects.isNull(this.typeConverterSupport)) {
            this.typeConverterSupport = defaultTypeConverter(this.vertx);
        }
        
        // 解析处理器
        processHandler();
        
        // 用户拓展的优先添加
        for (MirageRestfulConfigurer webMvcConfigurer : this.restfulConfigurer) {
            webMvcConfigurer.registerHttpMessageConverter(this.httpMessageConverters);
            webMvcConfigurer.registerExceptionResolver(this.exceptionResolvers);
            webMvcConfigurer.registerExceptionHandler(this.exceptionHandler);
            webMvcConfigurer.registerHandlerInterceptor(this.interceptorMappings);
            webMvcConfigurer.registryConversion(this.typeConverterSupport);
            webMvcConfigurer.registerStaticResourceHandler(this.staticResourceHandlerRegistry);
        }
        
        // 默认静态资源处理器
        defaultStaticResourceHandler(this.staticResourceHandlerRegistry);
        
        // 请求响应主体方法转换器
        defaultHttpMessageConverters(this.vertx, this.httpMessageConverters);
        RequestResponseBodyMethodProcessor requestResponseBodyMethodProcessor = new RequestResponseBodyMethodProcessor(this.httpMessageConverters);
        
        // 拦截器
        defaultInterceptorMappings(this.vertx, this.interceptorMappings);
        HandlerInterceptorComposite interceptorComposite = new HandlerInterceptorComposite();
        interceptorComposite.addInterceptor(this.interceptorMappings);
        
        // 请求参数解析器
        HandleMethodArgumentResolverComposite handleMethodArgumentResolverComposite = new HandleMethodArgumentResolverComposite();
        handleMethodArgumentResolverComposite.addResolver(requestResponseBodyMethodProcessor);
        defaultMethodArgumentResolver(this.vertx, handleMethodArgumentResolverComposite);
        
        // web 绑定初始化器
        ConfigurableWebBindingInitializer webBindingInitializer = createWebBindingInitializer(this.vertx);
        if (Objects.isNull(this.validator)) {
            this.validator = defaultValidator(this.vertx);
        }
        webBindingInitializer.setValidator(this.validator);
        
        webBindingInitializer.setTypeConverter(this.typeConverterSupport);
        defaultConversionRegistry(this.vertx, this.typeConverterSupport);
        
        // 结果转换器
        HandleMethodReturnValueHandlerComposite handleMethodReturnValueHandlerComposite = new HandleMethodReturnValueHandlerComposite();
        handleMethodReturnValueHandlerComposite.addHandler(requestResponseBodyMethodProcessor);
        defaultMethodReturnValueHandler(this.vertx, handleMethodReturnValueHandlerComposite);
        
        // 异常解析器
        HandlerExceptionResolverComposite exceptionResolverComposite = new HandlerExceptionResolverComposite();
        exceptionResolverComposite.addExceptionResolvers(buildExceptionResolvers(this.vertx));
        
        // 基于注解的请求方法映射处理器
        this.interceptorComposite = interceptorComposite;
        this.argumentResolverComposite = handleMethodArgumentResolverComposite;
        this.returnValueHandlerComposite = handleMethodReturnValueHandlerComposite;
        this.exceptionResolverComposite = exceptionResolverComposite;
        this.webBindingInitializer = webBindingInitializer;
    }
    
    /**
     * 确定指定候选bean的类型，如果识别为处理程序类型，则调用 {@link #detectHandlerMethods}。
     *
     * @see #isHandler
     * @see #detectHandlerMethods
     */
    protected void processHandler() {
        ApplicationContext applicationContext = obtainApplicationContext();
        if (Objects.isNull(applicationContext)) return;
        
        for (Map.Entry<String, Class<?>> entry : getCandidateBeans().entrySet()) {
            String beanName = entry.getKey();
            Class<?> beanType = entry.getValue();
            
            if (beanType == null) continue;
            
            // 处理器
            if (isHandler(beanType)) {
                detectHandlerMethods(beanName);
            }
            
            // 增强处理器
            if (isHandlerAdvice(beanType)) {
                detectHandlerAdviceMethods(beanName);
            }
            
            // 拦截器
            if (HandlerInterceptor.class.isAssignableFrom(beanType)) {
                detectHandlerInterceptors(beanName, applicationContext);
            }
            
            // 配置器
            if (MirageRestfulConfigurer.class.isAssignableFrom(beanType)) {
                this.restfulConfigurer.add(applicationContext.getBean(beanName));
            }
        }
    }
    
    /**
     * 判断是否为处理器
     *
     * @param beanType 被检查的bean的类型
     * @see Controller
     */
    protected boolean isHandler(Class<?> beanType) {
        return AnnotatedElementUtils.hasAnnotation(beanType, Controller.class);
    }
    
    /**
     * 判断是否为特殊化的处理器
     *
     * @param beanType 被检查的bean的类型
     * @see ControllerAdvice
     */
    protected boolean isHandlerAdvice(Class<?> beanType) {
        return AnnotatedElementUtils.hasAnnotation(beanType, ControllerAdvice.class);
    }
    
    /**
     * 在指定的处理程序bean中查找处理程序方法并注册
     */
    public void detectHandlerMethods(Object handler) {
        Class<?> handlerType;
        // 如果类型为字符串则当做对象名称使用
        if (handler instanceof String) {
            if (obtainApplicationContext() == null) return;
            handlerType = obtainApplicationContext().getBeanType((String) handler);
        } else {
            handlerType = handler.getClass();
        }
        
        if (handlerType == null || !isHandler(handlerType)) return;
        
        // 筛选支持映射的方法
        Map<Method, RequestMappingInfo> methods = new HashMap<>();
        
        for (Method method : ReflectUtil.getMethods(handlerType)) {
            try {
                RequestMappingInfo mappingInfoForMethod = getMappingInfoForMethod(method, handlerType);
                
                if (Objects.nonNull(mappingInfoForMethod)) {
                    methods.put(method, mappingInfoForMethod);
                }
                
            } catch (Throwable ex) {
                throw new IllegalStateException("处理程序类[" + handlerType.getName() + "]的无效映射方法:  " + method, ex);
            }
        }
        
        
        // 打印日志
        if (log.isTraceEnabled()) {
            log.trace(formatMappings(handlerType, methods));
        }
        
        // 循环注册方法
        methods.forEach((method, mapping) -> registerHandlerMethod(handler, method, mapping));
    }
    
    /**
     * 在指定的处理程序bean中查找特殊化处理程序方法并注册
     */
    protected void detectHandlerAdviceMethods(Object handlerAdvice) {
        Object handlerAdviceBean = handlerAdvice;
        
        // 如果类型为字符串则当做对象名称使用
        if (handlerAdvice instanceof String) {
            if (obtainApplicationContext() == null) return;
            handlerAdviceBean = obtainApplicationContext().getBean((String) handlerAdvice);
        }
        
        Class<?> handlerAdviceType = handlerAdviceBean.getClass();
        if (!isHandlerAdvice(handlerAdviceType)) return;
        
        // 注册异常处理解析器
        exceptionHandlerExceptionResolver.registerExceptionHandler(handlerAdviceBean);
    }
    
    /**
     * 拦截器的注解式拓展
     */
    protected void detectHandlerInterceptors(String beanName, @NotNull ApplicationContext applicationContext) {
        WebInterceptor webInterceptor = applicationContext.findAnnotationOnBean(beanName, WebInterceptor.class);
        if (webInterceptor == null) return;
        
        this.interceptorMappings.add(
                InterceptorMappingInfo.builder()
                        .interceptorName(StrUtil.isBlank(webInterceptor.interceptorName()) ? webInterceptor.interceptorName() : beanName)
                        .includePatterns(webInterceptor.includePatterns())
                        .excludePatterns(webInterceptor.excludePatterns())
                        .handler(applicationContext.getBean(beanName))
                        .order(webInterceptor.order())
                        .build());
    }
    
    @Override
    protected HandlerMethod createHandlerMethod(Object handler, Method method) {
        // 支持定义 对象名称 的处理器
        if (handler instanceof String) {
            ApplicationContext applicationContext = obtainApplicationContext();
            if (Objects.isNull(applicationContext)) {
                throw new IllegalArgumentException("应用上下文为空，无法创建基于应用上下文的 HandlerMethod！");
            }
            return new HandlerMethod((String) handler, applicationContext, method);
        }
        return super.createHandlerMethod(handler, method);
    }
    
    /**
     * 确定应用程序上下文中候选bean的名称
     */
    protected Map<String, Class<?>> getCandidateBeans() {
        ApplicationContext applicationContext = obtainApplicationContext();
        if (Objects.isNull(applicationContext)) {
            throw new IllegalArgumentException("应用上下文为空，无法解析处理器！");
        }
        
        return applicationContext.getBeanClassForType(Object.class);
    }
    
    /**
     * 构建异常解析器
     */
    protected List<HandlerExceptionResolver> buildExceptionResolvers(Vertx vertx) {
        // 默认异常处理器
        this.exceptionHandler.forEach(this.exceptionHandlerExceptionResolver::registerExceptionHandler);
        defaultExceptionHandlerExceptionResolver(vertx, this.exceptionHandlerExceptionResolver);
        
        this.exceptionResolvers.add(this.exceptionHandlerExceptionResolver);
        defaultExceptionResolvers(vertx, this.exceptionResolvers);
        return this.exceptionResolvers;
    }
    
}
